package com.cgsrp.cgsrp_baby.service.impl;

import com.alibaba.fastjson.JSON;
import com.cgsrp.cgsrp_baby.dao.BabyMapper;
import com.cgsrp.cgsrp_baby.dao.ChildParentMapper;
import com.cgsrp.cgsrp_baby.dao.PhotopathVideoMapper;
import com.cgsrp.cgsrp_baby.domain.Baby;
import com.cgsrp.cgsrp_baby.domain.ChildParent;
import com.cgsrp.cgsrp_baby.domain.PhotopathVideo;
import com.cgsrp.cgsrp_baby.domain.vo.BabyVo;
import com.cgsrp.cgsrp_baby.domain.vo.PicVo;
import com.cgsrp.cgsrp_baby.domain.vo.PicsVo;
import com.cgsrp.cgsrp_baby.service.BabyService;
import com.cgsrp.utils.MinioUtils;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.github.pagehelper.PageHelper;
import org.elasticsearch.Version;

import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest;
import org.elasticsearch.action.bulk.BulkRequest;
import org.elasticsearch.action.bulk.BulkResponse;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.action.support.master.AcknowledgedResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.client.indices.GetIndexRequest;
import org.elasticsearch.common.text.Text;
import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.query.MatchQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import java.beans.Transient;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

@Service
public class BabyServiceImpl implements BabyService {
    @Resource
    private BabyMapper babyMapper;

    @Resource
    private ChildParentMapper childParentMapper;

    @Resource
    private PhotopathVideoMapper photopathVideoMapper;

    @Resource
    private RestHighLevelClient restHighLevelClient;

    @Resource
    private RedisTemplate redisTemplate;

    @Resource
    private MinioUtils minioUtils;


    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @Override
    public PicsVo getPics(int userId, String disc, int pageNum, int pageSize) {
        boolean hasIndex = checkUserIndex(userId);
        List<PicVo> picVos = new ArrayList<>();
        SearchHits hits;
        if (!hasIndex) {
            boolean b = parseBabyPics(userId);
        }

        hits = getHits(disc,userId,pageNum,pageSize);

        try {
            for (SearchHit hit : hits) {
                String sourceAsString = hit.getSourceAsString();
                PicVo picVo = new ObjectMapper().readValue(sourceAsString,PicVo.class);
                Map<String, HighlightField> highlightFields = hit.getHighlightFields();
                HighlightField describe = highlightFields.get("describe");
                StringBuilder n_describe= new StringBuilder();
                if (describe!=null){
                    Text[] fragments = describe.fragments();
                    for (Text fragment : fragments) {
                        n_describe.append(fragment);
                    }
                    picVo.setDescribe(n_describe.toString());
                }
                picVos.add(picVo);
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        return getPicsVo(picVos,userId);
    }


    @Override
    public List<Baby> getBabies(int userId) {
        PageHelper.clearPage();
        return babyMapper.selectByParentId(userId);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean addBaby(Baby baby,Integer userId,String relationship) {
        if (babyMapper.insert(baby)>0){
            ChildParent childParent = new ChildParent();
            childParent.setChildId(baby.getId());
            childParent.setParentId(userId);
            childParent.setRelationship(relationship);
            return childParentMapper.insertSelective(childParent)>0;
        };
        return false;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public String uploadVideo(Integer babyId, String describe, MultipartFile fileCover, MultipartFile file,Integer userId) {
        try {
            String filePath = minioUtils.upload(file);
            String coverPath = minioUtils.upload(fileCover);
            PhotopathVideo video = new PhotopathVideo();
            video.setBabyId(babyId);
            video.setDescribe(describe);
            video.setCoverpath(coverPath);
            video.setPhotopath(filePath);
            video.setSign(1);
            int i = photopathVideoMapper.insert(video);
            if (i>0){
                DeleteIndexRequest request = new DeleteIndexRequest("es"+userId);
                AcknowledgedResponse response = restHighLevelClient.indices().delete(request, RequestOptions.DEFAULT);
                if (response.isAcknowledged()) {
                    stringRedisTemplate.delete("REDIS"+ userId);
                    return "添加成功";
                }
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        return "添加失败";
    }

    @Override
    public String uploadPhotos(Integer babyId, String describe, MultipartFile[] photo, Integer userId) {
        try {
            if (photo!=null&&photo.length>0) {
                for (MultipartFile file : photo) {
                    String path = minioUtils.upload(file);
                    PhotopathVideo photopathVideo = new PhotopathVideo();
                    photopathVideo.setSign(0);
                    photopathVideo.setBabyId(babyId);
                    photopathVideo.setDescribe(describe);
                    photopathVideo.setCoverpath(path);
                    photopathVideo.setPhotopath(path);
                    int i = photopathVideoMapper.insert(photopathVideo);
                    if (i>0){
                        DeleteIndexRequest request = new DeleteIndexRequest("es"+userId);
                        AcknowledgedResponse response = restHighLevelClient.indices().delete(request, RequestOptions.DEFAULT);
                        if (response.isAcknowledged()) {
                            stringRedisTemplate.delete("REDIS"+ userId);
                            return "添加成功";
                        }
                    }
                }
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        return "添加失败";
    }

    private SearchHits getHits(String disc,int userId,int pageNum,int pageSize){
        try {
            SearchRequest searchRequest = new SearchRequest("es"+userId);
            SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
            // 分页
            sourceBuilder.from(pageNum);
            sourceBuilder.size(pageSize);
            MatchQueryBuilder termQuery = null;
            if (!(disc == null || disc.isEmpty())) {
                termQuery = QueryBuilders.matchQuery("describe", disc);
            }
            HighlightBuilder highlightBuilder=new HighlightBuilder();
            highlightBuilder.requireFieldMatch(false);//多个高亮显示
            highlightBuilder.preTags("<font color='red'>");
            highlightBuilder.postTags("</font>");
            highlightBuilder.field("describe");
            sourceBuilder.highlighter(highlightBuilder);
            sourceBuilder.query(termQuery);
            sourceBuilder.timeout(new TimeValue(30, TimeUnit.SECONDS));
            searchRequest.source(sourceBuilder);
            SearchResponse search = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
            return search.getHits();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    private boolean parseBabyPics(int userId){
        try {
            List<PicVo> picVos = getPicVos(userId);
            BulkRequest bulkRequest = new BulkRequest();
            bulkRequest.timeout("2m");
            for (PicVo picVo : picVos) {
                bulkRequest.add(
                        new IndexRequest()
                                .index("es"+userId)
                                .id(picVo.getPhotoId().toString())
                                .source(JSON.toJSONString(picVo), XContentType.JSON)
                );
            }
            BulkResponse bulk = restHighLevelClient.bulk(bulkRequest, RequestOptions.DEFAULT);
            return !bulk.hasFailures();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    private List<PicVo> getPicVos(int userId) {
        HashOperations ops = redisTemplate.opsForHash();
        List<PicVo> picVos = ops.values("REDIS"+ userId);
        if (picVos.isEmpty()){
            Integer[] myBabies = babyMapper.foundChildByParentId(userId);
            if (myBabies.length>0){
                picVos = photopathVideoMapper.foundByBabies(myBabies);
                //存入redis
                for (PicVo picVo : picVos) {
                    System.out.println("picVo1 = " + picVo);
                    ops.put("REDIS"+ userId,picVo.getPhotoId(),picVo);
                }
                // 设置键的过期时间为1小时
                redisTemplate.expire("REDIS"+ userId, 1, TimeUnit.HOURS);
                //从redis取出来
                picVos=ops.values("REDIS"+ userId);
            }
        }
        return picVos;
    }

    private boolean checkUserIndex(int userId) {
        try {
            GetIndexRequest request = new GetIndexRequest("es"+userId);
            return restHighLevelClient.indices().exists(request, RequestOptions.DEFAULT);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
    private PicsVo getPicsVo(List<PicVo> picVos,int userId) {
        PicsVo picsVo = null;
        try {
            picsVo = new PicsVo();
            picsVo.setPicVos(picVos);
            SearchRequest request=new SearchRequest();
            request.indices("es"+userId);
            request.source(new SearchSourceBuilder().query(QueryBuilders.matchAllQuery()));
            restHighLevelClient.search(request,RequestOptions.DEFAULT);
            SearchResponse response = restHighLevelClient.search(request, RequestOptions.DEFAULT);
            SearchHits hits = response.getHits();
            picsVo.setTotalSize(hits.getTotalHits().value);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        return picsVo;
    }
}
